;; supercollider/buffer-shared.scm - (c) rohan drape, 2003-2005

;; A mechanism for sharing SC3 buffers.  A shared buffer is acquired
;; by submitting a form to 'buffer/shared'.  If a buffer exists for
;; that form the existing buffer identifier is returned, else a new
;; buffer is created.  The system maintains a use count for each
;; buffer so buffers must be released when they are no longer in use
;; by calling 'buffer/shared-release' with the buffer to be release.
;; The 'buffer/shared-collect' procedure frees unused buffers.

(define-structure buffer/shared (id count))

;; The data table.

(define-global buffer/shared-table (make-table))

;; Add `n' to the use count for `e'.

(define (buffer/shared-use! e n)
  (let ((c (+ (buffer/shared-count e) n)))
    (if (< c 0) 
	(error "buffer/shared-use!: negative use count"))
    (set-buffer/shared-count! e (+ (buffer/shared-count e) n)))
  e)

;; The only legal form at present is a file name string.

(defineV (make-buffer/shared form)
  (let ((e (table-get* (buffer/shared-table) form)))
    (if e
	(buffer/shared-id (buffer/shared-use! e 1))
	(if (not (string? form))
	    (error "buffer/shared: Illegal form" form)
	    (let ((b (buffer-alloc-read form)))
	      (table-put! (buffer/shared-table) form (make-buffer/shared* b 1))
	      b)))))

;; Decrement the use count for the buffer id `n'.

(define (buffer/shared-release b)
  (table-for-each (lambda (_ e) 
		    (if (eq? b (buffer/shared-id e))
			(buffer/shared-use! e -1)))
		  (buffer/shared-table)))

;; Free all buffers with a use count of zero.

(define (buffer/shared-collect)
  (error "buffer/shared-collect: not implemented"))
